/**
* All Rights Reserved , Copyright (C) 2022 , 青岛鼎信通讯股份有限公司
*
* MpmProjectOverdueRecordService
* 销售项目超期记录
*
* 修改纪录
* 2022-04-21 版本：1.0 houyuhang 创建。
* @version 版本：1.0
* @author 作者：houyuhang
* 创建日期：2022-04-21
*/
package com.topscomm.mpm.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.topscomm.basic.util.SQLAdapter;
import com.topscomm.mpm.MpmSystemConst;
import com.topscomm.mpm.pojo.*;
import com.topscomm.pub.util.ConvertUtil;
import com.topscomm.pub.util.StringBufferProxy;
import org.apache.poi.hpsf.Decimal;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import com.topscomm.mpm.service.IMpmProjectOverdueRecordService;
import com.topscomm.mpm.service.impl.auto.MpmProjectOverdueRecordServiceAuto;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;

@Service(value = "mpmProjectOverdueRecordService")
@Scope(value = "singleton")
public class MpmProjectOverdueRecordService extends MpmProjectOverdueRecordServiceAuto implements IMpmProjectOverdueRecordService {
    /**
     * @author: houyuhang
     * @date: 2022-04-22
     * @param paraMap
     * @return
     * @description:获取超期统计信息
     * @modify:
     */
    public List<Map<String, Object>> loadOverDueSummary(Map<String, Object> paraMap) {
	    // 根据时间范围获取项目
        List<Map<String, Object>> projectEnableList = this.queryProjectEnable(paraMap);
        // 根据时间范围获取里程碑及任务
        List<Map<String, Object>> milepostEnableList = this.queryMilepostEnable(paraMap);
        Map<String, List<Map<String, Object>>> milepostEnableMap = milepostEnableList.stream().
                collect(Collectors.groupingBy(item -> ConvertUtil.convertToString(item.get("milepostdept"))));
        // 根据时间范围获取任务
        List<Map<String, Object>> taskEnableList = this.queryTaskEnable(paraMap);
        Map<String, List<Map<String, Object>>> taskEnableMap = taskEnableList.stream().
                collect(Collectors.groupingBy(item -> ConvertUtil.convertToString(item.get("taskdept"))));
        // 获取项目、里程碑及任务、任务超期时间和次数信息
        List<Map<String, Object>> overdueList = this.queryOverdueInfo(paraMap);
        Map<String, List<Map<String, Object>>> overdueMap = overdueList.stream().
                collect(Collectors.groupingBy(item -> ConvertUtil.convertToString(item.get("overduedept"))));
        // 拼接各字段到一个list中
        this.concatAllMap(projectEnableList, milepostEnableMap, taskEnableMap, overdueMap);
        this.setDispFields(projectEnableList);
        // 计算合计内容
        this.calculateTotal(projectEnableList);
        // 计算平均值
        this.calculateAverage(projectEnableList);
	    return projectEnableList;
    }
    /**
     * @author: houyuhang
     * @date: 2022-04-22
     * @param paraMap
     * @return
     * @description:根据时间范围获取项目
     * @modify:
     */
    public List<Map<String, Object>> queryProjectEnable(Map<String, Object> paraMap) {
        StringBufferProxy sql = new StringBufferProxy();
        if (!ObjectUtil.isEmpty(paraMap.get("startdate")) && !ObjectUtil.isEmpty(paraMap.get("enddate"))) {
            String startdateSql = SQLAdapter.toDateLong(ConvertUtil.convertToString(paraMap.get("startdate")) + " 00:00:00");
            String enddateSql = SQLAdapter.toDateLong(ConvertUtil.convertToString(paraMap.get("enddate")) + " 23:59:59");
            // 1或2 1、计划开始时间小于等于选定的结束时间且实际（没有选择计划）完成时间大于等于选定的开始时间 2、计划结束时间小于选定的开始时间且项目处于进行中状态
            sql.appendSingle(" {0} <= {1} and {2} >= {3} or {4} < {5} and {6} = {7} ", MpmProjectEntity.FieldPlanstartdate, enddateSql,
                    SQLAdapter.isNull(MpmProjectEntity.FieldActualenddate, MpmProjectEntity.FieldPlanenddate), startdateSql,
                    MpmProjectEntity.FieldPlanenddate, startdateSql, MpmProjectEntity.FieldProjectstate, MpmSystemConst.ProjectState.ExecuteStateCode);
        }
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("whereSql", sql.toString());
        return this.queryMap(dataMap,"queryProjectEnable");
    }
    /**
     * @author: houyuhang
     * @date: 2022-04-22
     * @param paraMap
     * @return
     * @description:根据时间范围获取里程碑及任务
     * @modify:
     */
    public List<Map<String, Object>> queryMilepostEnable(Map<String, Object> paraMap) {
        StringBufferProxy sql = new StringBufferProxy();
        if (!ObjectUtil.isEmpty(paraMap.get("startdate")) && !ObjectUtil.isEmpty(paraMap.get("enddate"))) {
            String startdateSql = SQLAdapter.toDateLong(ConvertUtil.convertToString(paraMap.get("startdate")) + " 00:00:00");
            String enddateSql = SQLAdapter.toDateLong(ConvertUtil.convertToString(paraMap.get("enddate")) + " 23:59:59");
            // 1或2 1、计划开始时间小于等于选定的结束时间且实际（没有选择计划）完成时间大于等于选定的开始时间 2、计划结束时间小于选定的开始时间且里程碑及任务处于未达成状态
            sql.appendSingle(" mpmprojectplan.{0} <= {1} and {2} >= {3} or {4} < {5} and {6} = {7} ", MpmProjectPlanEntity.FieldSubmitdate, enddateSql,
                    SQLAdapter.isNull(MpmProjectMilepostEntity.FieldActualfinishtime, MpmProjectMilepostEntity.FieldPlanfinishtime), startdateSql,
                    MpmProjectMilepostEntity.FieldPlanfinishtime, startdateSql, MpmProjectMilepostEntity.FieldMilepoststate, MpmSystemConst.MilepostStateCode.MilepostIncompleteCode);
        }
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("whereSql", sql.toString());
        return this.queryMap(dataMap,"queryMilepostEnable");
    }
    /**
     * @author: houyuhang
     * @date: 2022-04-22
     * @param paraMap
     * @return
     * @description:根据时间范围获取任务
     * @modify:
     */
    public List<Map<String, Object>> queryTaskEnable(Map<String, Object> paraMap) {
        StringBufferProxy sql = new StringBufferProxy();
        if (!ObjectUtil.isEmpty(paraMap.get("startdate")) && !ObjectUtil.isEmpty(paraMap.get("enddate"))) {
            String startdateSql = SQLAdapter.toDateLong(ConvertUtil.convertToString(paraMap.get("startdate")) + " 00:00:00");
            String enddateSql = SQLAdapter.toDateLong(ConvertUtil.convertToString(paraMap.get("enddate")) + " 23:59:59");
            String taskState = "'" + MpmSystemConst.TaskStateCode.TaskNotStartCode + "','" + MpmSystemConst.TaskStateCode.TaskIncompleteCode + "'";
            // 1或2 1、计划开始时间小于等于选定的结束时间且实际（没有选择计划）完成时间大于等于选定的开始时间 2、计划结束时间小于选定的开始时间且任务处于未开始/进行中状态
            sql.appendSingle(" {0}.{1} <= {2} and {3} >= {4} or {0}.{5} < {6} and {7} in ({8}) ",
                    MpmProjectTaskEntity.tableName, MpmProjectTaskEntity.FieldPlanstartdate, enddateSql,
                    SQLAdapter.isNull(MpmProjectTaskEntity.tableName + "." + MpmProjectTaskEntity.FieldActualenddate, MpmProjectTaskEntity.tableName + "." + MpmProjectTaskEntity.FieldPlanenddate), startdateSql,
                    MpmProjectTaskEntity.FieldPlanenddate, startdateSql, MpmProjectTaskEntity.FieldTaskstate, taskState);
        }
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("whereSql", sql.toString());
        return this.queryMap(dataMap,"queryTaskEnable");
    }
    /**
     * @author: houyuhang
     * @date: 2022-04-22
     * @param paraMap
     * @return
     * @description:获取项目、里程碑及任务、任务超期时间和次数信息
     * @modify:
     */
    public List<Map<String, Object>> queryOverdueInfo(Map<String, Object> paraMap) {
        StringBufferProxy sql = new StringBufferProxy();
        if (!ObjectUtil.isEmpty(paraMap.get("startdate")) && !ObjectUtil.isEmpty(paraMap.get("enddate"))) {
            String startdateSql = SQLAdapter.toDateLong(ConvertUtil.convertToString(paraMap.get("startdate")) + " 00:00:00");
            String enddateSql = SQLAdapter.toDateLong(ConvertUtil.convertToString(paraMap.get("enddate")) + " 23:59:59");
            // 计划开始时间小于等于选定的结束时间且实际（没有选择计划）完成时间大于等于选定的开始时间
            sql.appendSingle(" {0} <= {1} and {2} >= {3} ", MpmProjectOverdueRecordEntity.FieldOverduestartdate,
                    enddateSql, SQLAdapter.isNull(MpmProjectOverdueRecordEntity.FieldOverdueenddate, SQLAdapter.getDate()), startdateSql);
        }
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("whereSql", sql.toString());
        return this.queryMap(dataMap,"queryOverdueInfo");
    }
    /**
     * @author: houyuhang
     * @date: 2022-04-22
     * @return
     * @description:计算项目/里程碑及任务/任务超期平均值
     * @modify:
     */
    public void calculateAverage(List<Map<String, Object>> projectEnableList) {
        for (Map<String, Object> projectEnableMap : projectEnableList) {
            BigDecimal projectAll = ConvertUtil.convertToBigDecimal(projectEnableMap.get("projectall"));
            BigDecimal overdueProjectTime = ConvertUtil.convertToBigDecimal(projectEnableMap.get("overdueprojecttime"));
            BigDecimal overdueProjectNum = ConvertUtil.convertToBigDecimal(projectEnableMap.get("overdueprojectnum"));
            BigDecimal milepostAll = ConvertUtil.convertToBigDecimal(projectEnableMap.get("milepostall"));
            BigDecimal overdueMilepostTime = ConvertUtil.convertToBigDecimal(projectEnableMap.get("overduemileposttime"));
            BigDecimal overdueMilepostNum = ConvertUtil.convertToBigDecimal(projectEnableMap.get("overduemilepostnum"));
            BigDecimal taskAll = ConvertUtil.convertToBigDecimal(projectEnableMap.get("taskall"));
            BigDecimal overdueTaskTime = ConvertUtil.convertToBigDecimal(projectEnableMap.get("overduetasktime"));
            BigDecimal overdueTaskNum = ConvertUtil.convertToBigDecimal(projectEnableMap.get("overduetasknum"));
            projectEnableMap.put("averageoverdueprojecttime", overdueProjectTime.divide(projectAll, 2, BigDecimal.ROUND_HALF_UP));
            projectEnableMap.put("averageoverdueprojectnum", overdueProjectNum.divide(projectAll,2, BigDecimal.ROUND_HALF_UP));
            if (milepostAll.equals(BigDecimal.ZERO)) {
                projectEnableMap.put("averageoverduemileposttime", new BigDecimal(0));
                projectEnableMap.put("averageoverduemilepostnum", new BigDecimal(0));
            } else {
                projectEnableMap.put("averageoverduemileposttime", overdueMilepostTime.divide(milepostAll,2, BigDecimal.ROUND_HALF_UP));
                projectEnableMap.put("averageoverduemilepostnum", overdueMilepostNum.divide(milepostAll,2, BigDecimal.ROUND_HALF_UP));
            }
            if (taskAll.equals(BigDecimal.ZERO)) {
                projectEnableMap.put("averageoverduetasktime", new BigDecimal(0));
                projectEnableMap.put("averageoverduetasknum", new BigDecimal(0));
            } else {
                projectEnableMap.put("averageoverduetasktime", overdueTaskTime.divide(taskAll,2, BigDecimal.ROUND_HALF_UP));
                projectEnableMap.put("averageoverduetasknum", overdueTaskNum.divide(taskAll,2, BigDecimal.ROUND_HALF_UP));
            }
        }
    }
    /**
     * @author: houyuhang
     * @date: 2022-04-22
     * @return
     * @description:拼接各字段到一个list中
     * @modify:
     */
    public void concatAllMap(List<Map<String,Object>> projectEnableList, Map<String, List<Map<String,Object>>> milepostEnableMap, Map<String, List<Map<String,Object>>> taskEnableMap, Map<String, List<Map<String,Object>>> overdueMap) {
        for (Map<String, Object> projectEnableMap : projectEnableList) {
            String deptCommonCode = ConvertUtil.convertToString(projectEnableMap.get("deptcommoncode"));
            if (!CollectionUtil.isEmpty(milepostEnableMap.get(deptCommonCode))) {
                projectEnableMap.putAll(milepostEnableMap.get(deptCommonCode).get(0));
            } else {
                this.concatMapZero(projectEnableMap, "milepost");
            }
            if (!CollectionUtil.isEmpty(taskEnableMap.get(deptCommonCode))) {
                projectEnableMap.putAll(taskEnableMap.get(deptCommonCode).get(0));
            } else {
                this.concatMapZero(projectEnableMap, "task");
            }
            if (!CollectionUtil.isEmpty(overdueMap.get(deptCommonCode))) {
                projectEnableMap.putAll(overdueMap.get(deptCommonCode).get(0));
            } else {
                this.concatMapZero(projectEnableMap, "overdue");
            }
        }
    }
    /**
     * @author: houyuhang
     * @date: 2022-04-22
     * @return
     * @description:不存在的值null转换成0
     * @modify:
     */
    public void concatMapZero(Map<String, Object> projectEnableMap,String type) {
        if ("milepost".equals(type)) {
            projectEnableMap.put(MpmSystemConst.OverdueStat.milepost, new BigDecimal(0));
        } else if("task".equals(type)) {
            projectEnableMap.put(MpmSystemConst.OverdueStat.task, new BigDecimal(0));
        } else if("overdue".equals(type)) {
            for (String str : MpmSystemConst.OverdueStat.overdue) {
                projectEnableMap.put(str, new BigDecimal(0));
            }
        }
    }
    /**
     * @author: houyuhang
     * @date: 2022-04-23
     * @return
     * @description:计算统计信息
     * @modify:
     */
    public void calculateTotal(List<Map<String, Object>> projectEnableList) {
        if (CollectionUtil.isEmpty(projectEnableList)) {
            return;
        }
        Set<String> projectkey = projectEnableList.get(0).keySet();
        Map<String, Object> totalMap = new HashMap<>();
        String[] noNeedTotal = {"deptcommoncode", "milepostdept", "taskdept", "overduedept"};
        List<String> noNeedTotalList = new ArrayList<>(Arrays.asList(noNeedTotal));
        for (String key : projectkey) {
            if ("dispdeptcommoncode".equals(key)) {
                totalMap.put(key, "合计");
            } else if (!noNeedTotalList.contains(key)) {
                BigDecimal bigDecimal = new BigDecimal(0);
                for (Map<String, Object> projectEnableMap : projectEnableList) {
                    bigDecimal = bigDecimal.add(ConvertUtil.convertToBigDecimal(projectEnableMap.get(key)));
                }
                totalMap.put(key, bigDecimal);
            }
        }
        projectEnableList.add(totalMap);
    }
}
